package cn.chiship.bs.api.core.util;

import cn.chiship.sdk.core.base.BaseResult;
import cn.chiship.sdk.core.base.constants.BaseConstants;
import cn.chiship.sdk.core.enums.BaseResultEnum;
import cn.chiship.sdk.core.exception.custom.BusinessException;
import cn.chiship.sdk.core.util.CsvUtils;
import cn.chiship.sdk.core.util.ExcelXSSFUtil;
import cn.chiship.sdk.core.util.ExcelHSSFUtil;
import cn.chiship.sdk.core.util.OutUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 导出工具
 *
 * @author lijian
 */
public class ExportUtil {
    private static ExportUtil exportUtil;

    private ExportUtil() {
    }

    public static synchronized ExportUtil getInstance() {
        if (exportUtil == null) {
            exportUtil = new ExportUtil();
        }
        return exportUtil;
    }

    public byte[] getExportBytesByType(String exportType, String fileName, String sheetName, List<String> labels, List<List<String>> valueList) throws Exception {
        byte[] bytes;
        if (labels.size() != valueList.get(0).size()) {
            return new byte[0];
        }
        labels.add(0, "序号");
        AtomicInteger index = new AtomicInteger(1);
        valueList.forEach(item -> {
            item.add(0, String.valueOf(index.getAndIncrement()));
        });
        switch (exportType) {
            case BaseConstants.EXPORT_FORMAT_XLS:
                bytes = ExcelHSSFUtil.getWriteExcelBytes(fileName, sheetName, labels, valueList);
                break;
            case BaseConstants.EXPORT_FORMAT_XLSX:
                bytes = ExcelXSSFUtil.getWriteExcelBytes(fileName, sheetName, labels, valueList);
                break;
            case BaseConstants.EXPORT_FORMAT_CSV:
                bytes = CsvUtils.getWriteCsvBytes(labels, valueList);
                break;
            case BaseConstants.EXPORT_FORMAT_JSON:
                JSONArray jsonArray = new JSONArray();
                for (int i = 0; i < valueList.size(); i++) {
                    HashMap<String, String> map = new LinkedHashMap<>();
                    for (int j = 0; j < labels.size(); j++) {
                        map.put(labels.get(j), valueList.get(i).get(j));
                    }
                    JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(map));
                    jsonArray.add(jsonObject);
                }
                bytes = jsonArray.toString().getBytes(StandardCharsets.UTF_8);
                break;
            case BaseConstants.EXPORT_FORMAT_TXT:
                StringBuilder write = new StringBuilder();
                String doubleTab = "        ";
                String enter = "\r\n";
                for (String lab : labels) {
                    write.append(lab).append(doubleTab);
                }
                write.append(enter);
                for (List<String> list : valueList) {
                    for (String val : list) {
                        write.append(val).append(doubleTab);
                    }
                    write.append(enter);
                }
                bytes = write.toString().getBytes(StandardCharsets.UTF_8);
                break;
            default:
                throw new BusinessException("不识别的导出格式：" + exportType);
        }
        return bytes;
    }

    public void exportByType(HttpServletResponse response, String exportType, String fileName, byte[] bytes) throws Exception {
        OutputStream os = response.getOutputStream();
        switch (exportType) {
            case BaseConstants.EXPORT_FORMAT_XLS:
            case BaseConstants.EXPORT_FORMAT_XLSX:
                response.setContentType("application/vnd.ms-excel;charset=utf-8");
                break;
            case BaseConstants.EXPORT_FORMAT_CSV:
                response.setContentType("application/ms-txt.numberformat:@;charset=GBK");
                break;
            case BaseConstants.EXPORT_FORMAT_JSON:
                response.setContentType("text/plain;charset=utf-8");
                break;
            case BaseConstants.EXPORT_FORMAT_TXT:
                response.setContentType("text/plain");
                break;
            default:
                throw new BusinessException("不识别的输出格式：" + exportType);
        }
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + "." + exportType);

        os.write(bytes);
        os.flush();
        os.close();
    }


    /**
     * 导出
     */
    public void exportByType(HttpServletResponse response, String exportType, String fileName, String sheetName, List<String> labels, List<List<String>> valueList) throws Exception {
        if (valueList.isEmpty()) {
            BaseResult baseResult = BaseResult.error(BaseResultEnum.FAILED, "没有找到符合条件的记录!");
            OutUtil.writeJson(response, baseResult);
            return;
        }
        if (labels.size() != valueList.get(0).size()) {
            BaseResult baseResult = BaseResult.error(BaseResultEnum.FAILED, "标题列数与数值列数不匹配!");
            OutUtil.writeJson(response, baseResult);
            return;
        }
        labels.add(0, "序号");
        AtomicInteger index = new AtomicInteger(1);
        valueList.forEach(item -> {
            item.add(0, String.valueOf(index.getAndIncrement()));
        });

        switch (exportType) {
            /**
             * 导出Excel
             */
            case BaseConstants.EXPORT_FORMAT_XLS:
            case BaseConstants.EXPORT_FORMAT_XLSX:
                exportExcel(fileName, sheetName, labels, valueList, response, exportType);
                break;
            /**
             * 导出CSV
             */
            case BaseConstants.EXPORT_FORMAT_CSV:
                exportCsv(fileName, labels, valueList, response, exportType);
                break;
            /**
             * 导出JSON
             */
            case BaseConstants.EXPORT_FORMAT_JSON:
                JSONArray jsonArray = new JSONArray();
                for (int i = 0; i < valueList.size(); i++) {
                    HashMap<String, String> map = new LinkedHashMap<>();
                    for (int j = 0; j < labels.size(); j++) {
                        map.put(labels.get(j), valueList.get(i).get(j));
                    }
                    JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(map));
                    jsonArray.add(jsonObject);
                }
                exportJson(fileName, jsonArray, response, exportType);
                break;
            /**
             * 导出TXT
             */
            case BaseConstants.EXPORT_FORMAT_TXT:
                exportTxt(fileName, labels, valueList, response, exportType);
                break;
            default:
                BaseResult baseResult = BaseResult.error(BaseResultEnum.FAILED, "不支持的导出格式");
                OutUtil.writeJson(response, baseResult);
        }
    }

    public void exportCsv(String fileName, List<String> columnLabel, List<List<String>> columnValue, HttpServletResponse response, String exportType) throws IOException {
        response.setContentType("application/ms-txt.numberformat:@;charset=GBK");
        response.setHeader("Content-Disposition", "attachment; filename=" + fileName + "." + exportType);
        OutputStream os = response.getOutputStream();
        CsvUtils.writeCsv(os, columnLabel, columnValue);
        os.flush();
        os.close();
    }

    public void exportJson(String fileName, JSONArray jsonArray, HttpServletResponse response, String exportType) throws IOException {
        response.setContentType("text/plain;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment; filename=" + fileName + "." + exportType);
        OutputStream os = response.getOutputStream();
        os.write(jsonArray.toString().getBytes(StandardCharsets.UTF_8));
        os.flush();
        os.close();
    }

    public void exportTxt(String fileName, List<String> columnLabel, List<List<String>> columnValue, HttpServletResponse response, String exportType) throws IOException {
        StringBuilder write = new StringBuilder();
        String doubleTab = "        ";
        String enter = "\r\n";
        for (String lab : columnLabel) {
            write.append(lab).append(doubleTab);
        }
        write.append(enter);
        for (List<String> list : columnValue) {
            for (String val : list) {
                write.append(val).append(doubleTab);
            }
            write.append(enter);
        }
        response.setContentType("text/plain");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + "." + exportType);
        BufferedOutputStream buff = new BufferedOutputStream(response.getOutputStream());
        buff.write(write.toString().getBytes(StandardCharsets.UTF_8));
        buff.flush();
        buff.close();
    }

    /**
     * 导出Excel
     *
     * @param fileName    文件名称
     * @param sheetName   sheet名称
     * @param headerNames 标题
     * @param values      值集合
     * @param response    响应
     * @param exportType  导出类型
     * @throws Exception 异常
     */
    public void exportExcel(String fileName, String sheetName, List<String> headerNames, List<List<String>> values, HttpServletResponse response, String exportType) throws Exception {
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        OutputStream os = response.getOutputStream();
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + "." + exportType);
        if (BaseConstants.EXPORT_FORMAT_XLS.equals(exportType)) {
            ExcelHSSFUtil.writeExcel(os, fileName, sheetName, headerNames, values);
        } else {
            ExcelXSSFUtil.writeExcel(os, fileName, sheetName, headerNames, values);
        }
        os.flush();
        os.close();

    }
}
